package com.baitiaojun.moments.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baitiaojun.api.domain.moments.UserMoments;
import com.baitiaojun.api.exception.ConditionException;
import com.baitiaojun.api.util.ConstantUtil;
import com.baitiaojun.api.vo.PageInfo;
import com.baitiaojun.moments.factory.UserMomentsFactory;
import com.baitiaojun.moments.feign.UserFeign;
import com.baitiaojun.moments.mapper.UserMomentsMapper;
import com.baitiaojun.moments.service.DailyMomentsService;
import com.baitiaojun.moments.service.DuplicateService;
import com.baitiaojun.moments.service.MomentsService;
import com.baitiaojun.moments.support.RedisSupport;
import com.baitiaojun.moments.util.BloomFilterUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @类名 MessageServiceImpl
 * @描述 TODO 返回值感知异常的状态
 * @作者 白条君
 * @创建日期 2022/11/27 14:11
 * @版本 1.0
 */
@Service
public class MomentsServiceImpl implements MomentsService {

    @Resource
    private UserMomentsMapper userMomentsMapper;

    @Autowired
    private RedisSupport redisSupport;

    @Lazy
    @Autowired
    private DailyMomentsService dailyMomentsService;

    @Lazy
    @Autowired
    private DuplicateService duplicateService;

    @Autowired
    private UserFeign userFeign;

    @Autowired
    private UserMomentsFactory userMomentsFactory;

    @Autowired
    private BloomFilterUtil bloomFilterUtil;

    private static final Object subscribedMomentsLock = new Object();

    private static final Object currentUserMomentsLock = new Object();

    @Override
    public void addUserMoments(UserMoments userMoments) throws ConditionException {
        int res = userMomentsMapper.insertSelective(userMoments);
        if (res == 0) {
            throw new ConditionException("添加用户动态失败");
        }
    }

    @Override
    public PageInfo getSubscribedUserMoments(Long userId, Integer pageNo, Integer pageSize) throws Exception {
        if (ObjectUtils.isEmpty(userId)) {
            throw new ConditionException("参数异常");
        }
        //获取关注用户userinfoid
        Set<Long> followingUserIds = userFeign.getFollowingUserIds(userId);
        if (followingUserIds.size() == 0) {
            return PageInfo.builder().pageList(new ArrayList<>()).size(0).build();
        }
        //使用布隆过滤器过滤，防止缓存穿透
//        followingUserIds = bloomFilterUtil.filterMomentsUserIds("subscribed", followingUserIds);
        //获取自己所关注用户的动态
        List<Object> page = redisSupport.getPage("subscribed" + userId, pageNo, pageSize);
        if (page == null) {
            throw new ConditionException("获取缓存数据异常");
        }
        List<UserMoments> pageList = JSONObject.parseArray(JSONObject.toJSONString(page), UserMoments.class);
        if (pageList.size() == 0) {
//            synchronized (subscribedMomentsLock) {
                pageList = JSONObject.parseArray(JSONObject.toJSONString(page), UserMoments.class);
                if (pageList.size() == 0) {
                    //获取关注用户的动态
                    if (ObjectUtils.isNotEmpty(followingUserIds) && followingUserIds.size() > 0) {
                        List<UserMoments> followingUserMomentsList = this.batchGetUserMomentsOthers(followingUserIds, (pageNo - 1) * pageSize, pageSize);
                        this.setMoments(followingUserMomentsList, pageList, "subscribed" + userId);
                    }
                }
//            }
            List<UserMoments> userMoments = pageList
                    .stream()
                    .sorted((userMoments1, userMoments2) -> userMoments2.getCreatetime().compareTo(userMoments1.getCreatetime()))
                    .collect(Collectors.toList());
            return PageInfo.builder().pageList(userMoments).size(userMoments.size()).build();
        }
        return PageInfo.builder().pageList(page).size(page.size()).build();
    }

    @Override
    public List<UserMoments> batchGetUserMomentsOthers(Set<Long> followingUserIds, Integer pageNo, Integer pageSize) {
        return userMomentsMapper.batchSelectByUserId(followingUserIds, pageNo, pageSize);
    }

    @Override
    public void cancelUserMoments(Long id, Long userId) throws Exception {
        UserMoments userMoments = this.userMomentsMapper.selectTypeByContentId(id);
        if (ObjectUtils.isEmpty(userMoments)) {
            throw new ConditionException("此动态不存在");
        }
        String type = userMoments.getType();
        if(ConstantUtil.VIDEO_TYPE.equals(type)) {
            throw new ConditionException("视频类型不可删除");
        }
        //清除缓存
        this.cancelUserMoments(type, id);
        redisSupport.delete("self" + userId);
        redisSupport.delete("self" + userId + ":page");
        redisSupport.asyncDelete(userId);
    }

    @Override
    public UserMoments getUserMoments(Long contentId) {
        return userMomentsMapper.selectUserIdByContentId(contentId);
    }

    @Override
    public List<Object> getCurrentUserMoments(Long userId, Integer pageNo, Integer pageSize) throws Exception {
        if (ObjectUtils.isEmpty(userId)) {
            throw new ConditionException("参数异常");
        }
        //使用布隆过滤器过滤，防止缓存穿透
//        Set<Long> userIds = bloomFilterUtil.filterMomentsUserIds("self", Collections.singleton(userId));
        List<Object> page = new ArrayList<>();
        //如果用户没有发布过动态就返回空数组
//        if (userIds.size() == 0) {
//            return page;
//        }
//        userId = userIds.iterator().next();
        //获取自己发布的动态
        String key = "self" + userId;
        page = redisSupport.getPage(key, pageNo, pageSize);
        if (page == null) {
            throw new ConditionException("获取缓存数据异常");
        }
        List<UserMoments> pageList = JSONObject.parseArray(JSONObject.toJSONString(page), UserMoments.class);
        if (pageList.size() == 0) {
//            synchronized (currentUserMomentsLock) {
                pageList = JSONObject.parseArray(JSONObject.toJSONString(page), UserMoments.class);
                if (pageList.size() == 0) {
                    //获取自己发布的动态
                    if (ObjectUtils.isNotEmpty(userId)) {
                        List<UserMoments> selfUserMomentsList = this.getUserMomentsSelf(userId, (pageNo - 1) * pageSize, pageSize);
                        this.setMoments(selfUserMomentsList, pageList, key);
                    }
                }
//            }
            return pageList
                    .stream()
                    .sorted((userMoments1, userMoments2) -> userMoments2.getCreatetime().compareTo(userMoments1.getCreatetime()))
                    .collect(Collectors.toList());
        }
        return page;
    }

    private List<UserMoments> getUserMomentsSelf(Long userId, Integer pageNo, Integer pageSize) {
        return userMomentsMapper.selectByUserId(userId, pageNo, pageSize);
    }

    @Transactional
    public void cancelUserMoments(String type, Long id) throws ConditionException {
        if(ConstantUtil.DAILY_TYPE.equals(type)) {
            dailyMomentsService.deleteDailyMoments(id);
        } else if (ConstantUtil.SPECIAL_COLUMN_TYPE.equals(type)) {

        }
        duplicateService.deleteDuplicateByContentId(this.userMomentsMapper.selectIdByContentId(id));
        int res = this.userMomentsMapper.deleteByContentId(id);
        if (res == 0) {
            throw new ConditionException("删除用户动态失败");
        }
    }

    @Override
    public void setMoments(List<UserMoments> userMomentsList, List<UserMoments> page, String key) throws Exception {
        for (UserMoments userMoments : userMomentsList) {
            Long contentid = userMoments.getContentid();
            String type = userMoments.getType();
            UserMoments moments = userMomentsFactory.createMoments(type, contentid, userMoments.getUserid(), userMoments);
            page.add(moments);
            redisSupport.setPage(key, String.valueOf(contentid), moments);
        }
    }

    @Override
    public Integer getMomentsCount(Long userId) {
        return userMomentsMapper.countMoments(userId);
    }
}